package com.cz.video.website.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cz.video.common.constant.CacheNames;
import com.cz.video.common.constant.ClientConstants;
import com.cz.video.common.core.domain.PageQuery;
import com.cz.video.common.core.page.TableDataInfo;
import com.cz.video.common.exception.ServiceException;
import com.cz.video.common.helper.LoginHelper;
import com.cz.video.common.utils.StringUtils;
import com.cz.video.common.utils.redis.RedisUtils;
import com.cz.video.website.domain.WebsiteLike;
import com.cz.video.website.domain.bo.WebsiteLikeBo;
import com.cz.video.website.domain.vo.WebsiteLikeVo;
import com.cz.video.website.mapper.WebsiteLikeMapper;
import com.cz.video.website.service.WebsiteLikeService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RSet;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 点赞 服务实现类
 * </p>
 *
 */
@Slf4j
@Service
@AllArgsConstructor
public class WebsiteLikeServiceImpl implements WebsiteLikeService {
  private final WebsiteLikeMapper likeMapper;

  @Override
  public TableDataInfo<WebsiteLikeVo> page(WebsiteLikeBo like, PageQuery pageQuery) {
    Page<WebsiteLikeVo> page = likeMapper.selectPageList(pageQuery.build(), this.buildQueryWrapper(like), LoginHelper.getUserId());
    return TableDataInfo.build(page);
  }

  @Override
  public List<WebsiteLikeVo> list(WebsiteLikeBo likeBo) {
    return likeMapper.selectWebsiteLikeList(this.buildQueryWrapper(likeBo));
  }

  @Override
  public WebsiteLikeVo get(Long id) {
    return likeMapper.selectVoById(id);
  }


  @Override
  public int add(WebsiteLikeBo like) {
    return likeMapper.insert(like);
  }

  @Override
  public int update(WebsiteLikeBo like) {

    return likeMapper.updateById(like);
  }

  @Override
  public int deleteByIds(Long[] ids) {
    return likeMapper.deleteBatchIds(Arrays.asList(ids));
  }

    @Override
    public boolean isLike(Long sourceId, Long clientUserId) {
        String cacheName = CacheNames.CLIENT_LIKE.split("#")[0] + ":like:" + sourceId;
        RSet<Object> set = RedisUtils.getClient().getSet(cacheName);
        boolean like= set.contains(clientUserId);
        //如果like为false,并且set在缓存不存在 再去数据库查一下
        if(!like&&!set.isExists()){
            RLock lock = RedisUtils.getClient().getLock(ClientConstants.LIKE_LOCK);
            try {
                //获取锁，这里就死等。留个释放时间以防万一
                lock.lock(1, TimeUnit.SECONDS);
                //这里有一点风险就是，该源id没有对应的点赞。导致多个线程都会查询一次
                if (!set.isExists()){
                    //查询给其点赞的用户id
                    Set<Long> idSet=likeMapper.selectUserIdsBySourceId(sourceId, ClientConstants.LIKE);
                    like=idSet.contains(clientUserId);
                    //放入缓存,这里没有把clientUserId也放进去
                    RedisUtils.setCacheSet(cacheName, idSet);
                    //设置过期时间
                    RedisUtils.getClient().getSet(cacheName).expire(Duration.ofHours(
                        Long.parseLong(StringUtils.substringBetween(CacheNames.CLIENT_LIKE,"#","h"))));
                }
            }catch (Exception e){
                log.error("加载点赞集合时出现问题");
                throw new ServiceException("点赞出现异常");
            }finally {
                lock.unlock();
            }
//            //查询给其点赞的用户id
//           Set<Long> idSet=likeMapper.selectUserIdsBySourceId(sourceId, WebsiteConstants.LIKE);
//           like=idSet.contains(clientUserId);
//           //放入缓存,这里没有把clientUserId也放进去
//           RedisUtils.setCacheSet(cacheName, idSet);
//           //设置过期时间
//           RedisUtils.getWebsite().getSet(cacheName).expire(Duration.ofHours(
//                   Long.parseLong(StringUtils.substringBetween(CacheNames.CLIENT_LIKE,"#","h"))));
        }
        return like;
    }

    @Override
    public boolean isDislike(Long sourceId, Long clientUserId) {
        String cacheName = CacheNames.CLIENT_LIKE.split("#")[0] + ":dislike:" + sourceId;
        RSet<Object> set = RedisUtils.getClient().getSet(cacheName);
        boolean dislike = set.contains(clientUserId);
        //如果dislike为false,并且set在缓存不存在 再去数据库查一下
        if(!dislike &&!set.isExists()){
            //查询给其点赞的用户id
            Set<Long> idSet=likeMapper.selectUserIdsBySourceId(sourceId, ClientConstants.DISLIKE);
            dislike =idSet.contains(clientUserId);
            //放入缓存,这里没有把clientUserId也放进去
            RedisUtils.setCacheSet(cacheName, idSet);
        }
        return dislike;
    }

    @Override
    public int delete(Long sourceId, Long userId) {
        return likeMapper.delete(Wrappers.<WebsiteLike> lambdaQuery()
            .eq(WebsiteLike::getSourceId, sourceId).eq(WebsiteLike::getUserId, userId));
    }

    @Override
    public int deleteByUserIds(Long[] ids) {
        return likeMapper.delete(Wrappers.<WebsiteLike> lambdaQuery()
                .eq(WebsiteLike::getUserId,LoginHelper.getUserId())
            .in(WebsiteLike::getUserId, (Object[]) ids));
    }


    /**
   * 根据查询条件构建query wrapper
   *
   * @param like 查询条件
   *
   * @return query wrapper
   */
  private Wrapper<WebsiteLike> buildQueryWrapper(WebsiteLikeBo like) {

      QueryWrapper<WebsiteLike> wrapper = Wrappers.query();
    wrapper
        .eq(ObjectUtil.isNotNull(like.getUserId()), "cl.user_id", like.getUserId())
        .eq(ObjectUtil.isNotNull(like.getType()), "cl.type", like.getType())
        .eq(ObjectUtil.isNotNull(like.getSourceId()), "cl.source_id", like.getSourceId())
        .eq(ObjectUtil.isNotNull(like.getLikedUserId()), "cl.liked_user_id", like.getLikedUserId());
    return wrapper;
  }
}
